#include "qdeviceserver.h"

#include "qbasedefine.h"

#include "../shared/xmlobject.h"

#include <QStringList>

QDeviceServer::QDeviceServer(tagServerInfo *info, QObject *parent) :
    QObject(parent),
    m_server_info(info),
    m_socket(new QUdpSocket),
    m_recv_send_socket(new QUdpSocket),
    m_timer(new QTimer)
{
    m_socket->bind(SERVER_HAND_READ,QUdpSocket::ReuseAddressHint);
    m_recv_send_socket->bind(SERVER_READ,QUdpSocket::ReuseAddressHint);
    m_timer->start(30);
    connect(m_socket,SIGNAL(readyRead()),this,SLOT(read()));
    connect(m_recv_send_socket,SIGNAL(readyRead()),this,SLOT(send_read()));
    connect(m_timer,SIGNAL(timeout()),this,SLOT(hand_timer()));
    m_last_date_time=QDateTime::currentDateTime();
}

QDeviceServer::~QDeviceServer()
{
    QString str=QString::number(SERVER_OFFLINE_CODE)+":"+m_server_info->m_uuid;
    m_socket->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,SERVER_HAND_WRITE);
    m_socket->close();
    m_recv_send_socket->close();
    delete m_recv_send_socket;
    delete m_socket;
    delete m_timer;
}

void QDeviceServer::read()
{
    QHostAddress    address;
    int size=m_socket->pendingDatagramSize();
    if(size<0)
    {
        return;
    }
    char *data=new char[size+1];
    int count=m_socket->readDatagram(data,size,&address);
    if(count>0)
    {
        data[count]=0;
        QString str=data;
        int s=str.indexOf(":");
        if(s>0)
        {
            QString code=str.left(s);
            QString value=str.mid(s+1);
            if(code.toInt()==NEW_DEVICE_CODE)
            {
                XMLObject xml;
                if(xml.load(value,0))
                {
                    if(xml.get_property("uuid")!=""
                            && xml.get_property("device_type")!=""
                            && xml.get_property("soft_version")!="")
                    {
                        tagDeviceInfo info;
                        info.m_uuid=xml.get_property("uuid");
                        info.m_device_ip=address.toIPv4Address();
                        info.m_device_type=xml.get_property("device_type");
                        info.m_project_name=xml.get_property("project_name");
                        info.m_soft_version=xml.get_property("soft_version");
                        info.m_soft_status=xml.get_property("soft_status");
                        if(!m_device_hand.keys().contains(info.m_uuid))
                        {
                            search(address.toIPv4Address());
                        }
                        m_device_hand.insert(info.m_uuid,QDateTime::currentDateTime());
                        emit new_device(&info);
                    }
                }
            }
            else if(code.toInt()==DEVICE_HAND_CODE)
            {
                if(m_device_hand.keys().contains(value))
                {
                    m_device_hand.insert(value,QDateTime::currentDateTime());
                }
                else
                {
                    search(address.toIPv4Address());
                }
            }
            else if(code.toInt()==PROPERTY_CODE)
            {
                int p=value.indexOf(":");
                if(p>0)
                {
                    QString uuid=value.left(p);
                    QString pro=value.mid(p+1);
                    XMLObject xml;
                    if(xml.load(pro,0))
                    {
                        QList<XMLObject*> list=xml.get_children();
                        QStringList propertys;
                        foreach(XMLObject* o,list)
                        {
                            propertys<<(o->get_property("name")+"="+o->get_property("value"));
                        }

                        emit property_refresh(uuid,propertys);
                    }
                }
            }
            else if(code.toInt()==DEVICE_OFFLINE_CODE)
            {
                if(m_device_hand.keys().contains(value))
                {
                    emit device_offline(value);
                    m_device_hand.remove(value);
                }
            }

        }
    }
    delete data;
}

void QDeviceServer::send_read()
{
    QHostAddress    address;
    int size=m_recv_send_socket->pendingDatagramSize();
    if(size<0)
    {
        return;
    }
    char* data=new char[size+1];
    m_recv_send_socket->readDatagram(data,size,&address);
    data[size]=0;
    emit recv_data(QByteArray(data,size));
    delete data;
}

void QDeviceServer::hand_timer()
{
    QDateTime dt=QDateTime::currentDateTime();


    QMapIterator<QString,QDateTime>     it(m_device_hand);

    QStringList list;

    while(it.hasNext())
    {
        it.next();
        if(it.value().msecsTo(dt)>HAND_TIME_OUT)
        {
            list.append(it.key());
        }
    }

    foreach(const QString &str,list)
    {
        emit device_offline(str);
        m_device_hand.remove(str);
    }


    if(m_last_date_time.msecsTo(dt)>1000)
    {
        QString str=QString::number(SERVER_HAND_CODE)+":"+m_server_info->m_uuid;
        m_socket->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,SERVER_HAND_WRITE);
        m_last_date_time=dt;
    }
}

void QDeviceServer::search(int addr)
{
    XMLObject xml;
    xml.set_simple();
    xml.set_title(SERVER_TITLE);
    xml.set_property("uuid",m_server_info->m_uuid);
    xml.set_property("server_version",m_server_info->m_server_version);
    xml.set_property("server_type",m_server_info->m_server_type);

    QString str=QString::number(NEW_SERVER_CODE)+":"+xml.write();
    m_socket->writeDatagram(str.toLocal8Bit(),addr!=-1?QHostAddress(addr):QHostAddress::Broadcast,SERVER_HAND_WRITE);
}

void QDeviceServer::send_data(const QByteArray &data, int addr)
{
    m_recv_send_socket->writeDatagram(data,QHostAddress(addr),SERVER_WRITE);
}

tagServerInfo* QDeviceServer::get_server_info()
{
    return m_server_info;
}
